/**
 * @author David Young
 */
package csab.core.utility;
import java.io.*;
import java.util.Scanner;

import org.newdawn.slick.SlickException;

/**
 * Generate a random name based on the playername constructor 
 * input and the associated NOUN_DICT_1, NOUN_DICT_2, and ADJECTIVE_DICT
 * text files.
 * @author David Young
 */
public class NameGenerator {
	public static final String NOUN_DICT_1 = "resource/dictionary/noundict.txt";
	public static final String NOUN_DICT_2 = "resource/dictionary/noundict2.txt";
	public static final String ADJECTIVE_DICT = "resource/dictionary/adjectivedict.txt";
	private Scanner noun1 = null, noun2 = null, adjective = null;
	private String playername;
	private int nd1count, nd2count, adjcount;
	private boolean reset;

	/**
	 * Constructor for this class.
	 * @param playername The name of the player.
	 * @throws SlickException
	 */
    public NameGenerator(String playername) throws SlickException {
    	this.playername = playername;
    	try {
    		noun1 = new Scanner(new File(NOUN_DICT_1));
    		noun2 = new Scanner(new File(NOUN_DICT_2));
    		adjective = new Scanner(new File(ADJECTIVE_DICT));
    		nd1count = count(NOUN_DICT_1);
    		nd2count = count(NOUN_DICT_2);
    		adjcount = count(ADJECTIVE_DICT);
    		reset = true;
    	}
    	catch(FileNotFoundException e)
    	{
    		throw new SlickException("Could not find dictionary files!");
    	}
    	catch(IOException e)
    	{
    		throw new SlickException("Could not find dictionary files!");
    	}
    }
    
    private void reset() throws FileNotFoundException
    {
		noun1 = new Scanner(new File(NOUN_DICT_1));
		noun2 = new Scanner(new File(NOUN_DICT_2));
		adjective = new Scanner(new File(ADJECTIVE_DICT));
    }
    
    /**
     * Free all resources allocated to this NameGenerator.
     * Do not use this object after calling this.
     */
    public void release() 
    {
    	noun1.close();
		noun2.close();
		adjective.close();
    }

    /**
     * Generate a name based on the playername
     * provided to the constructor.
     * @return A pseudo-random generated name.
     * @throws SlickException
     */
    public String generateName() throws SlickException
    {
    	if(reset)
    	{
			try {
				reset();
			} catch (FileNotFoundException e) {
				throw new SlickException("Could not find dictionary files!");
			}
    	}
    	int randn1 = 0;
    	int randn2 = 0;
    	int randa1 = 0;
    	randn1 = (int)(Math.random() * nd1count );
    	randn2 = (int)(Math.random() * nd2count );
    	randa1 = (int)(Math.random() * adjcount );
    	String name = playername + " and the ";
    	String temp;

    	for(int k = 0; k < randa1; k++)
    	{
    		adjective.nextLine();
    	}
    	temp = adjective.nextLine();
    	temp = temp.substring(0,1).toUpperCase() + temp.substring(1);
    	name += temp + " ";

    	for(int i = 0; i < randn1; i++)
    	{
    		noun1.nextLine();
    	}
    	temp = noun1.nextLine();
    	temp = temp.substring(0,1).toUpperCase() + temp.substring(1);
    	name += temp + " of ";

    	for(int j = 0; j < randn2; j++)
    	{
    		noun2.nextLine();
    	}

    	temp = noun2.nextLine();
    	temp = temp.substring(0,1).toUpperCase() + temp.substring(1);
    	name += temp;
    	reset = false;
    	return name;
    }
    
    /**
     * Generate a name and print it. Mostly designed for
     * testing.
     * @param args Not parsed.
     * @throws SlickException
     */
    public static void main(String[] args) throws SlickException
    {
    	NameGenerator gen = new NameGenerator("Ponder Stibbons");
    	System.out.println(gen.generateName());
    }

    /**
     * Count the number of lines (entries) contained 
     * within the dictionary files.
     * @param filename Name of the dictionary file.
     * @return The number of entries in the file.
     * @throws IOException
     */
    private int count(String filename) throws IOException 
    {
	    InputStream is = new BufferedInputStream(new FileInputStream(filename));
	    try {
	        byte[] c = new byte[1024];
	        int count = 0;
	        int readChars = 0;
	        boolean empty = true;
	        while ((readChars = is.read(c)) != -1) {
	            empty = false;
	            for (int i = 0; i < readChars; ++i) {
	                if (c[i] == '\n') {
	                    ++count;
	                }
	            }
	        }
	        return (count == 0 && !empty) ? 1 : count;
	    } finally {
	        is.close();
	    }
    }
}